package org.lemma.language;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import javax.annotation.Author;
import javax.annotation.Copyright;
import javax.annotation.Version;
import org.lemma.number.Natural;

/**
 * <p>
 *  TODO: Javadoc for {@code Expression}
 * </p>
 *
 * @author Christopher Beatty [christopher.beatty@gmail.com]
 * @version 1.0.0
 */
@Version(
    major   = "1",
    minor   = "0",
    patch   = "0",
    date    = "2006-10-10T12:00:00-5:00",
    authors = { @Author(name = "Christopher Beatty", email = "christopher.beatty@gmail.com") }
)
@Copyright
public class Expression<L extends Language<L>> implements Formula<L>, Serializable {

    /**
     * Determines if a de-serialized file is compatible with this class.
     *
     * Maintainers must change this value if and only if the new version
     * of this class is not compatible with old versions. See Sun docs
     * for <a href="http://java.sun.com/products/jdk/1.1/docs/guide
     * /serialization/spec/version.doc.html">details.</a>
     */
    private static final long serialVersionUID = 1L;

    private String operator = null;

    private List<Formula<L>> operands = new ArrayList<Formula<L>>();

    protected Expression() {

    }

    public Expression(String operator, Formula<L> ... operands) {
        this(operator, Arrays.asList(operands));
    }

    public Expression(String operator, List<Formula<L>> operands) {
        this();
        //Set the Operator
        if(operator != null) {
            this.operator = operator;
        } else {
            throw new IllegalArgumentException("Operator is NULL");
        }
        //Set the operands
        if(operands != null) {
            this.operands = Collections.unmodifiableList(operands);
        } else {
            new ArrayList<Formula<L>>();
        }
    }

    @Override
    public Natural arity() {
        return new Natural(this.operands().size());
    }

    @Override
    public String operator() {
        return this.operator;
    }

    @Override
    public List<Formula<L>> operands() {
        return this.operands;
    }

    @Override
    public Expression<L> clone() {
        List<Formula<L>> ops = new ArrayList<Formula<L>>(this.operands().size());
        for(Formula<L> formula : this.operands()) {
            if(formula != null) {
                ops.add(formula.clone());
            } else {
                ops.add(null);
            }
        }
        return new Expression<L>(new String(this.operator()), ops);
    }

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(this.operator());
        if(this.operands() != null && this.operands().size() > 0) {
            sb.append("(");
            for(Formula<L> formula : this.operands()) {
                sb.append(formula);
                sb.append(",");
            }
            sb.deleteCharAt(sb.length() - 1);
            sb.append(")");
        }
        return sb.toString();
    }

}
